/*
 * I2C双24C02 EEPROM访问程序
 * 功能：
 * a) 向U2(地址0xA0)的0x00地址开始写入'0'~'4'的共阴极段码
 * b) 从U2读出这5个字节，存入U3(地址0xA2)的0x10地址开始的5个单元
 */

#include <reg51.h>
#include <intrins.h>

// 定义I2C引脚
sbit SCL = P2^0;  // 时钟线
sbit SDA = P2^1;  // 数据线

// 共阴极数码管段码：0,1,2,3,4
unsigned char code SEG_CODE[5] = {0x3F, 0x06, 0x5B, 0x4F, 0x66};

// 延时函数
void delay_us(unsigned int t) {
    while(t--);
}

// I2C起始信号
void I2C_Start() {
    SDA = 1;
    SCL = 1;
    delay_us(5);
    SDA = 0;
    delay_us(5);
    SCL = 0;
}

// I2C停止信号
void I2C_Stop() {
    SDA = 0;
    SCL = 1;
    delay_us(5);
    SDA = 1;
    delay_us(5);
}

// I2C发送应答
void I2C_Ack() {
    SDA = 0;
    delay_us(2);
    SCL = 1;
    delay_us(5);
    SCL = 0;
    SDA = 1;
}

// I2C发送非应答
void I2C_NAck() {
    SDA = 1;
    delay_us(2);
    SCL = 1;
    delay_us(5);
    SCL = 0;
}

// I2C等待应答
bit I2C_WaitAck() {
    bit ack;
    SDA = 1;
    delay_us(2);
    SCL = 1;
    delay_us(2);
    ack = SDA;
    SCL = 0;
    return ack;
}

// I2C发送一个字节
void I2C_SendByte(unsigned char dat) {
    unsigned char i;
    for(i = 0; i < 8; i++) {
        SDA = (dat & 0x80) ? 1 : 0;
        dat <<= 1;
        delay_us(2);
        SCL = 1;
        delay_us(5);
        SCL = 0;
    }
    I2C_WaitAck();
}

// I2C接收一个字节
unsigned char I2C_ReceiveByte() {
    unsigned char i, dat = 0;
    SDA = 1;
    for(i = 0; i < 8; i++) {
        dat <<= 1;
        SCL = 1;
        if(SDA) dat |= 0x01;
        SCL = 0;
    }
    return dat;
}

// 向24C02写入数据
void EEPROM_Write(unsigned char device_addr, unsigned char addr, unsigned char *dat, unsigned char len) {
    unsigned char i;
    
    for(i = 0; i < len; i++) {
        I2C_Start();
        I2C_SendByte(device_addr);  // 器件地址 + 写
        I2C_SendByte(addr + i);     // 内存地址
        I2C_SendByte(dat[i]);       // 数据
        I2C_Stop();
        
        // 等待写入完成
        delay_us(10000);
    }
}

// 从24C02读取数据
void EEPROM_Read(unsigned char device_addr, unsigned char addr, unsigned char *dat, unsigned char len) {
    unsigned char i;
    
    I2C_Start();
    I2C_SendByte(device_addr);      // 器件地址 + 写
    I2C_SendByte(addr);             // 内存地址
    
    I2C_Start();
    I2C_SendByte(device_addr | 0x01);  // 器件地址 + 读
    
    for(i = 0; i < len - 1; i++) {
        dat[i] = I2C_ReceiveByte();
        I2C_Ack();
    }
    dat[len - 1] = I2C_ReceiveByte();
    I2C_NAck();
    I2C_Stop();
}

// 主函数
void main() {
    unsigned char buffer[5];
    unsigned char i;
    
    // 初始化
    SCL = 1;
    SDA = 1;
    
    // 功能a：向U2写入'0'~'4'的共阴极段码
    EEPROM_Write(0xA0, 0x00, (unsigned char *)SEG_CODE, 5);
    
    // 延时等待写入完成
    for(i = 0; i < 200; i++) delay_us(50000);
    
    // 功能b：从U2读出数据，写入U3
    EEPROM_Read(0xA0, 0x00, buffer, 5);      // 从U2读取
    EEPROM_Write(0xA2, 0x10, buffer, 5);     // 写入U3
    
    // 程序结束，进入死循环
    while(1);
}
